#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <iterator>
#include <ctime>

//#include "DataPower.h"
#include "DataImage.h"
#include "Clustering.h"

#define DATA_POWER_CONSUMPTION "../data/household_power_consumption.txt"
#define DATA_A1 "../data/a1.txt"
#define DATA_A1_OUTPUT "../data/a1_o.bmp"
#define DATA_BIRCH3 "../data/birch3.txt"
#define DATA_BIRCH3_OUTPUT "../data/birch3_o.bmp"
#define DATA_IN "../data/in.txt"
#define DATA_IN_OUTPUT "../data/in_o.bmp"
#define DATA_BMP_SMALL "../data/small.bmp"
#define DATA_BMP_SMALL_OUTPUT "../data/small_o.bmp"
#define DATA_BMP_MORE "../data/more.bmp"
#define DATA_BMP_LESS "../data/less.bmp"
#define DATA_BMP_LESS_OUTPUT "../data/less_o.bmp"
#define DATA_BMP_LETTERS "../data/letters.bmp"
#define DATA_BMP_LETTERS_OUTPUT "../data/letters_o.bmp"
#define DATA_BMP_CAPTCHA "../data/letters noise simple captcha.bmp"
#define DATA_BMP_CAPTCHA_OUTPUT "../data/letters noise simple captcha_o.bmp"

using namespace std;

//DATA_DATABASE_CLASS_NAME pdb;
DATA_DATABASE_CLASS_NAME pdb;
Clustering *cl;

/// program.exe (input_file.(txt|bmp)) (DBSCAN epsilon minpts|DENCLUE sigma xi) [dimDiv]
int main(int argc, char **argv)
{
    bool isDbscan = false;
    bool isBmp = false;
    string fnameop;
    char *inputFileName;
    string outputFileName;
    char *alg;
    double epsilon = 0;
    unsigned int minpts = 0;
    double sigma = 0;
    double xi = 0;
    int dimDiv = 1;
    if ((argc != 5) && (argc != 6)){
        cout << "Usage: program.exe (input_file.(txt|bmp)) (DBSCAN epsilon minpts|DENCLUE sigma xi) [dimDiv]" << endl;
        cout << argc << endl;
        return 0;
    }
    /// verify that input file exists
    inputFileName = argv[1];
    fnameop = "";
    fnameop.append(inputFileName);
    FILE * fp;
    fp = fopen (inputFileName,"r");
    if (fp!=NULL){
        printf("Input file\tOK\n");
        fclose (fp);
    } else {
        printf("Input file\tERROR\n");
        cout << "File [" << inputFileName << "] does not exist" << endl;
        return 0;
    }
    /// determine input file type
    vector<std::string> fn = split(fnameop, '.');
    if (0 == strcmp(fn.back().c_str(), "bmp")){
        isBmp = true;
        //cout << "bmp" << endl;
    } else if (0 == strcmp(fn.back().c_str(), "txt")){
        isBmp = false;
    } else {
        printf("Input file\tERROR\n");
        cout << "File [" << inputFileName << "] is not a .bmp neither .txt file" << endl;
        return 0;
    }
    /// prepare output file name
    fn.pop_back();
    fn.back().append("_o");

    /// determine algorithm selected and its parameters
    alg = argv[2];
    if (0 == strcmp(alg, "DBSCAN")){
        isDbscan = true;
        printf("Algorithm\tDBSCAN\n");
        epsilon = atof(argv[3]);
        minpts = atoi(argv[4]);
        fn.back().append("_DBSCAN");
        fn.back().append("_");
        fn.back().append(argv[3]);
        fn.back().append("_");
        fn.back().append(argv[4]);
        if (epsilon==0){
            printf("Param epsilon\tERROR, epsilon=%f\n", epsilon);
        } else {
            printf("Param epsilon\tOK, epsilon=%f\n", epsilon);
        }
        printf("Param minpts\tOK, minpts=%d\n", minpts);
    } else if (0 == strcmp(alg, "DENCLUE")){
        isDbscan = false;
        printf("Algorithm\tDENCLUE\n");
        sigma = atof(argv[3]);
        xi = atof(argv[4]);
        fn.back().append("_DENCLUE");
        fn.back().append("_");
        fn.back().append(argv[3]);
        fn.back().append("_");
        fn.back().append(argv[4]);
        if (sigma==0){
            printf("Param sigma\tERROR, sigma=%f\n", sigma);
        } else {
            printf("Param sigma\tOK, sigma=%f\n", sigma);
        }
        if (xi==0){
            printf("Param xi\tERROR, xi=%f\n", xi);
        } else {
            printf("Param xi\tOK, xi=%f\n", xi);
        }

    } else {
        printf("Algorithm\tERROR - not selected\n");
        return 0;
    }
    ///
    if (argc == 6){
        dimDiv = atoi(argv[5]);
        printf("Param dimDiv\tOK, dimDiv=%d\n", dimDiv);
    }



    /// generate output file name
    fn.push_back("bmp");
    const char* const delim = ".";
    std::ostringstream imploded;
    std::copy(fn.begin(), fn.end(), std::ostream_iterator<std::string>(imploded, delim));
    outputFileName = "";
    outputFileName.append(imploded.str());
    outputFileName = outputFileName.substr(0, outputFileName.size()-1);
    cout << "output filename " << outputFileName << endl;

    /// load database

    if (isBmp){
        if (pdb.loadFromBMP((char*)inputFileName, 0)==1){
            printf("DB load\t\tOK\n");
        } else {
            printf("DB load\t\tERROR\n");
            exit(1);
        }
    } else {
        if (pdb.load((char*)inputFileName, 0)==1){
            printf("DB load\t\tOK\n");
        } else {
            printf("DB load\t\tERROR\n");
            exit(1);
        }
    }

    /// time measure
    clock_t begin = clock();

    /// execute algorithm
    cl = new Clustering(&pdb);
    if (isDbscan){
        cl->dbscan(epsilon, minpts);
    } else {
        cl->denclue(5, 2);
    }
    printf("Clustering \t\tOK\n");
    delete cl;

    clock_t end = clock();
    double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
    printf("Elapsed time: %f\n", elapsed_secs);

    /// save output
    if (pdb.saveToBMP((char*)outputFileName.c_str(), dimDiv)==1){
        printf("BMP saving \t\tOK\n");
    } else {
        printf("BMP saving \t\tERROR\n");
    }




    /*if (pdb.load((char*)DATA_IN, 10000)==1){
        printf("DB load\t\tOK\n");
    } else {
        printf("DB load\t\tERROR\n");
        exit(1);
    }*/


    /// A1
    /*
    if (pdb.load((char*)DATA_A1, 100000)==1){
        printf("DB load\t\t\tOK\n");
    } else {
        printf("DB load\t\t\tERROR\n");
        exit(1);
    }
    */

    /// BIRCH3
    /*if (pdb.load((char*)DATA_BIRCH3, 100000)==1){
        printf("DB load\t\t\tOK\n");
    } else {
        printf("DB load\t\t\tERROR\n");
        exit(1);
    }*/

    /// BMP FILES

    /*if (pdb.loadFromBMP((char*)DATA_BMP_SMALL, 0)==1){
        printf("DB load\t\tOK\n");
    } else {
        printf("DB load\t\tERROR\n");
        exit(1);
    }*/



    //cl = new Clustering(&pdb);
    //cl->dbscan(5, 5);  // less  40 clusters
    //cl->dbscan(10, 5);  // less  5 clusters
    //cl->dbscan(3.5, 30);  // captcha
    //cl->dbscan(2.5, 18);  // captcha better
    //cl->dbscan(1500, 5);  // a1 1
    //cl->dbscan(1500, 9);  // a1 2
    //cl->dbscan(1500, 12);  // a1 3
    //cl->dbscan(1500, 15);  // a1 4
    //cl->dbscan(1500, 45);  // a1 5  20 clusters
    //cl->dbscan(1, 45);  // birch3 1

    // edge length/2, minimumObjectsInHypercubes*2*dimension
    //cl->denclue(5, 2);

    //delete cl;

    //printf("Clustering \t\tOK\n");

    /*if (pdb.saveToBMP((char*)DATA_BMP_SMALL_OUTPUT)==1){
        printf("BMP saving \t\tOK\n");
    } else {
        printf("BMP saving \t\tERROR\n");
    }*/

    /*
    if (pdb.saveToBMP((char*)DATA_A1_OUTPUT,200)==1){
        printf("BMP saving \t\tOK\n");
    } else {
        printf("BMP saving \t\tERROR\n");
    }
    */
    /*
    if (pdb.saveToBMP((char*)DATA_BIRCH3_OUTPUT,1000)==1){
        printf("BMP saving \t\tOK\n");
    } else {
        printf("BMP saving \t\tERROR\n");
    }
    */
    //getchar();


    return 0;
}


